//
// Created by Ivor_ on 2022/1/22.
//

#ifndef PHYSICAL_COMPUTING_PACKAGE_MATRIXCALCULATE_H
#define PHYSICAL_COMPUTING_PACKAGE_MATRIXCALCULATE_H

#include <time.h>
#include "matrixOperate.h"

double* dMatLVec(int* MatDims, double** mat, double* vec);
double* dMatRVec(int* MatDims, double** mat, double* vec);
_Complex double* cMatLVec(int* MatDims, _Complex double** mat, _Complex double* vec);
_Complex double* cMatRVec(int* MatDims, _Complex double** mat, _Complex double* vec);
double dMixVal(int* MatDims, double** mat, double* vecL, double* vecR);
_Complex double cMixVal(int* MatDims, _Complex double** mat, _Complex double* vecL, _Complex double* vecR);
double dQuadratic(int* MatDims, double** mat, double* vec);
_Complex double cQuadratic(int* MatDims, _Complex double** mat, _Complex double* vec);
double dRayleighQuo(int* MatDims, double** mat, double* vec);
_Complex double cRayleighQuo(int* MatDims, _Complex double** mat, _Complex double* vec);
double dTrace(int dim, double** matrix);
_Complex double cTrace(int dim, _Complex double** matrix);

double** * dNaiveMatMultiple(int* dims, double** matL, double** matR);
_Complex double** * cNaiveMatMultiple(int* dims, _Complex double** matL, _Complex double** matR);
double** * dNaiveMatHadamardMul(int* dims, double** mat1, double** mat2);
_Complex double** * cNaiveMatHadamardMul(int* dims, _Complex double** mat1, _Complex double** mat2);
double** * dNaiveKroneckerMul(int* dims, double** matL, double** matR);
_Complex double** * cNaiveKroneckerMul(int* dims, _Complex double** matL, _Complex double** matR);
double** * dNaiveMatInnMul(int* dims, double** matL, double** matR);
_Complex double** * cNaiveMatInnMul(int* dims, _Complex double** matL, _Complex double** matR);
double** * dNaiveMatOutMul(int* dims, double** matL, double** matR);
_Complex double** * cNaiveMatOutMul(int* dims, _Complex double** matL, _Complex double** matR);
double** * dUltraMatMultiple(int* dims, int count, ...);
_Complex double** * cUltraMatMultiple(int* dims, int count, ...);
double** * dUltraMatHadamardMul(int* dims, int count, ...);
_Complex double** * cUltraMatHadamardMul(int* dims, int count, ...);
double** * dUltraKroneckerMul(int* dims, int count, ...);
_Complex double** * cUltraKroneckerMul(int* dims, int count, ...);
double** * dUltraMatInnMul(int* dims, int count, ...);
_Complex double** * cUltraMatInnMul(int* dims, int count, ...);
double** * dUltraMatOutMul(int* dims, int count, ...);
_Complex double** * cUltraMatOutMul(int* dims, int count, ...);

struct dMatrixNaiveMultiple {
    double** * (*multiple)(int*, double**, double**);
    double** * (*hadamard)(int*, double**, double**);
    double** * (*kronecker)(int*, double**, double**);
    double** * (*inner)(int*, double**, double**);
    double** * (*outer)(int*, double**, double**);
};

struct cMatrixNaiveMultiple {
    _Complex double** * (*multiple)(int*, _Complex double**, _Complex double**);
    _Complex double** * (*hadamard)(int*, _Complex double**, _Complex double**);
    _Complex double** * (*kronecker)(int*, _Complex double**, _Complex double**);
    _Complex double** * (*inner)(int*, _Complex double**, _Complex double**);
    _Complex double** * (*outer)(int*, _Complex double**, _Complex double**);
};

struct dMatrixUltraMultiple {
    double** * (*multiple)(int*, int, ...);
    double** * (*hadamard)(int*, int, ...);
    double** * (*kronecker)(int*, int, ...);
    double** * (*inner)(int*, int, ...);
    double** * (*outer)(int*, int, ...);
};

struct cMatrixUltraMultiple {
    _Complex double** * (*multiple)(int*, int, ...);
    _Complex double** * (*hadamard)(int*, int, ...);
    _Complex double** * (*kronecker)(int*, int, ...);
    _Complex double** * (*inner)(int*, int, ...);
    _Complex double** * (*outer)(int*, int, ...);
};

struct dMatrixNaiveMultiple dMulN(void);
struct cMatrixNaiveMultiple cMulN(void);
struct dMatrixUltraMultiple dMulX(void);
struct cMatrixUltraMultiple cMulX(void);

void freeDMat(int lines, double** mat);
void freeCMat(int lines, _Complex double** mat);
void freeDVec(double* vec);
void freeCVec(_Complex double* vec);

void dSchmidt(int dim, double** matrix);
void cSchmidt(int dim, _Complex double** matrix);
double dDeterminant(int dim, double** matrix);
_Complex double cDeterminant(int dim, _Complex double** matrix);
double** dInverse(int dim, double** matrix);
_Complex double** cInverse(int dim, _Complex double** matrix);
double* dDiagJacobi(int dim, double** matrix, double** eigenVectors, double eps);
_Complex double* cDiagJacobi(int dim, _Complex double** matrix, _Complex double** eigenVectors, double eps);
void dSvd(int* dims, double** matrix, double* sigma, double** uuL, double** vvR, double eps, double*(*matDiagMathod)());
void cSvd(int* dims, _Complex double** matrix, double* sigma, _Complex double** uuL, _Complex double** vvR, double eps, _Complex double*(*matDiagMathod)());
double* dDiagPower(int dim, double** matrix, double** eigenVectors, double eps);
_Complex double* cDiagPower(int dim, _Complex double** matrix, _Complex double** eigenVectors, double eps);
double* dDiagPowerWithShift(int dim, double** matrix, double** eigenVectors, double shift, double eps);
_Complex double* cDiagPowerWithShift(int dim, _Complex double** matrix, _Complex double** eigenVectors, _Complex double shift, double eps);
double* dDiagAntiPowerWithShift(int dim, double** matrix, double** eigenVectors, double shift, double eps);
_Complex double* cDiagAntiPowerWithShift(int dim, _Complex double** matrix, _Complex double** eigenVectors, _Complex double shift, double eps);
double* dDiagRayleighQI(int dim, double** matrix, double** eigenVectors, double eps);
_Complex double* cDiagRayleighQI(int dim, _Complex double** matrix, _Complex double** eigenVectors, double eps);
double* dDiagQR(int dim, double** matrix, double** eigenVectors, double eps);
_Complex double* cDiagQR(int dim, _Complex double** matrix, _Complex double** eigenVectors, double eps);
double* dDiagQRWithAccAlpha(int dim, double** matrix, double** eigenVectors, double eps);
_Complex double* cDiagQRWithAccAlpha(int dim, _Complex double** matrix, _Complex double** eigenVectors, double eps);
double* dDiagQRWithAccBeta(int dim, double** matrix, double** eigenVectors, double eps);
_Complex double* cDiagQRWithAccBeta(int dim, _Complex double** matrix, _Complex double** eigenVectors, double eps);

#endif //PHYSICAL_COMPUTING_PACKAGE_MATRIXCALCULATE_H
